package br.univap.aed.utils;

import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import br.univap.aed.cenario1.sort.QuickSortListaEncadeada;
import br.univap.aed.cenario1.sort.QuickSortRegistro;
import br.univap.aed.cenario1.sort.QuicksortInteiro;
import br.univap.aed.cenario1.utils.ListaEncadeada;
import br.univap.aed.cenario1.utils.Registro;
import br.univap.aed.cenario2.sort.QuickSortBasico;
import br.univap.aed.cenario2.sort.QuickSortInPlace;
import br.univap.aed.cenario2.sort.QuickSortIterativo;
import br.univap.aed.cenario2.sort.QuickSortMediano;
import br.univap.aed.cenario3.sort.MergeSort;

/**
 * Classe que realiza toda a an�lise dos algoritmos, calculando estat�sticas e
 * gerando arquivos de sa�da
 * 
 */
public class RunAnalise {

	private List<Estatistica> listEstatisticas;
	private List<Estatistica> listEstatisticasCenario2;
	private List<Estatistica> listEstatisticasCenario3;
	private Estatistica estatisticaInteiros;
	private Estatistica estatisticaListaEncadeada;
	private Estatistica estatisticaRegistros;

	private Estatistica estatisticaBasico;
	private Estatistica estatisticaInPlace;
	private Estatistica estatisticaIterativo;
	private Estatistica estatisticaMediano;
	private Estatistica estatisticaMerge;

	private ArrayList<Integer> teste;
	private Integer vetor[];

	public RunAnalise() {

	}

	/**
	 * Criar o vetor de inteiros que serão utilizados nos método que realizam
	 * análise dos cenários 2 e 3
	 * 
	 * @param semente
	 * @param tamanho
	 */
	public void setCenario(int semente, int tamanho) {
		teste = QuickSortUtils.geraInteiros(semente, tamanho + 1);
		vetor = new Integer[tamanho];
	}

	/**
	 * Executa o algoritmo de QuickSort que utiliza uma lista encadeada
	 * 
	 * @param semente
	 *            inteiro usado para gera��o de n�meros aleat�rios
	 * @param tamanho
	 *            define o tamanho de itens do vetor
	 */
	public void quickSortListaEncadeada(int semente, int tamanho) {
		if (estatisticaListaEncadeada == null) {
			estatisticaListaEncadeada = new Estatistica();
			estatisticaListaEncadeada.setNome("QuickSort Lista Encadeada");
		}

		ListaEncadeada lista = QuickSortUtils.geraListaEncadeada(semente,
				tamanho);

		QuickSortListaEncadeada q = new QuickSortListaEncadeada();

		double inicio = System.currentTimeMillis();
		lista = q.partition(lista, QuickSortUtils.sortear(lista.tamanho()));
		double fim = System.currentTimeMillis();

		double tempoTotal = fim - inicio;

		estatisticaListaEncadeada.getTempo().add(tempoTotal);
		estatisticaListaEncadeada.getComparacoes().add(q.getComparacoes());
		estatisticaListaEncadeada.getCopias().add(q.getCopias());
		estatisticaListaEncadeada.getElementos().add(tamanho);
	}

	/**
	 * Executa o algoritmo de QuickSort que utiliza um vetor de inteiros
	 * 
	 * @param semente
	 *            inteiro usado para gera��o de n�meros aleat�rios
	 * @param tamanho
	 *            define o tamanho de itens do vetor
	 */
	public void quickSortVetorInteiro(int semente, int tamanho) {
		if (estatisticaInteiros == null) {
			estatisticaInteiros = new Estatistica();
			estatisticaInteiros.setNome("QuickSort Vetor Inteiros");
		}

		ArrayList<Integer> vetor = QuickSortUtils
				.geraInteiros(semente, tamanho);
		QuicksortInteiro q = new QuicksortInteiro();

		double inicio = System.currentTimeMillis();
		vetor = q.partition(vetor, QuickSortUtils.sortear(vetor.size()));
		double fim = System.currentTimeMillis();

		double tempoTotal = fim - inicio;

		estatisticaInteiros.getTempo().add(tempoTotal);
		estatisticaInteiros.getComparacoes().add(q.getComparacoes());
		estatisticaInteiros.getCopias().add(q.getCopias());
		estatisticaInteiros.getElementos().add(tamanho);

	}

	/**
	 * Executa o algoritmo de QuickSort que utiliza um vetor de registros
	 * 
	 * @param semente
	 *            inteiro usado para gera��o de n�meros aleat�rios
	 * @param tamanho
	 *            define o tamanho de itens do vetor
	 */
	public void quickSortVetorRegistros(int semente, int tamanho) {
		if (estatisticaRegistros == null) {
			estatisticaRegistros = new Estatistica();
			estatisticaRegistros.setNome("QuickSort Vetor Registros");
		}

		Vector<Registro> vetorRegistros = QuickSortUtils.geraVetorRegistros(
				semente, tamanho);
		QuickSortRegistro q = new QuickSortRegistro();

		double inicio = System.currentTimeMillis();
		vetorRegistros = q.partition(vetorRegistros,
				QuickSortUtils.sortear(vetorRegistros.size()));
		double fim = System.currentTimeMillis();

		double tempoTotal = fim - inicio;

		estatisticaRegistros.getTempo().add(tempoTotal);
		estatisticaRegistros.getComparacoes().add(q.getComparacoes());
		estatisticaRegistros.getCopias().add(q.getCopias());
		estatisticaRegistros.getElementos().add(tamanho);
	}

	/**
	 * Executa o QuickSort Basico para um vetor de inteiros
	 */
	public void quickSortBasico() {
		if (estatisticaBasico == null) {
			estatisticaBasico = new Estatistica();
			estatisticaBasico.setNome("QuickSort Basico");
		}
		teste.toArray(vetor);
		QuickSortBasico q = new QuickSortBasico();

		// Come�ando a ordenar
		double inicio = System.currentTimeMillis();
		q.sort(vetor);
		double fim = System.currentTimeMillis();

		double tempoTotal = fim - inicio;
		q.cleanVetorSort();

		estatisticaBasico.getTempo().add(tempoTotal);
		estatisticaBasico.getComparacoes().add(q.getComparacoes());
		estatisticaBasico.getCopias().add(q.getCopias());
		estatisticaBasico.getElementos().add(vetor.length);
	}

	/**
	 * Executa o QuickSort InPlace para um vetor de inteiros
	 */
	public void quickSortInPlace() {
		if (estatisticaInPlace == null) {
			estatisticaInPlace = new Estatistica();
			estatisticaInPlace.setNome("QuickSort InPlace");
		}

		teste.toArray(vetor);
		QuickSortInPlace q = new QuickSortInPlace();

		double inicio = System.currentTimeMillis();
		q.sort(vetor);
		double fim = System.currentTimeMillis();
		double tempoTotal = fim - inicio;
		q.cleanVetorSort();

		estatisticaInPlace.getTempo().add(tempoTotal);
		estatisticaInPlace.getComparacoes().add(q.getComparacoes());
		estatisticaInPlace.getCopias().add(q.getCopias());
		estatisticaInPlace.getElementos().add(vetor.length);
	}

	/**
	 * Excecuta o QuickSort Iterativo para um vetor de inteiros
	 */
	public void quickSortIterativo() {
		if (estatisticaIterativo == null) {
			estatisticaIterativo = new Estatistica();
			estatisticaIterativo.setNome("QuickSort Iterativo");
		}
		teste.toArray(vetor);
		QuickSortIterativo q = new QuickSortIterativo();

		double inicio = System.currentTimeMillis();
		q.sort(vetor);
		double fim = System.currentTimeMillis();
		double tempoTotal = fim - inicio;
		q.cleanVetorSort();

		estatisticaIterativo.getTempo().add(tempoTotal);
		estatisticaIterativo.getComparacoes().add(q.getComparacoes());
		estatisticaIterativo.getCopias().add(q.getCopias());
		estatisticaIterativo.getElementos().add(vetor.length);
	}

	/**
	 * Executa o QuickSort Mediana para um vetor de inteiros
	 */
	public void quickSortMediana() {
		if (estatisticaMediano == null) {
			estatisticaMediano = new Estatistica();
			estatisticaMediano.setNome("QuickSort Mediano");
		}
		teste.toArray(vetor);
		QuickSortMediano q = new QuickSortMediano();

		double inicio = System.currentTimeMillis();
		q.sort(vetor);
		double fim = System.currentTimeMillis();

		double tempoTotal = fim - inicio;
		q.cleanVetorSort();

		estatisticaMediano.getTempo().add(tempoTotal);
		estatisticaMediano.getComparacoes().add(q.getComparacoes());
		estatisticaMediano.getCopias().add(q.getCopias());
		estatisticaMediano.getElementos().add(vetor.length);
	}

	/**
	 * Executa o MergeSort para um vetor de inteiros
	 */
	public void mergeSort() {
		if (estatisticaMerge == null) {
			estatisticaMerge = new Estatistica();
			estatisticaMerge.setNome("Merge Sort");
		}
		teste.toArray(vetor);
		MergeSort m = new MergeSort();

		double inicio = System.currentTimeMillis();
		m.sort(vetor);
		double fim = System.currentTimeMillis();

		double tempoTotal = fim - inicio;
		m.cleanVetorSort();

		estatisticaMerge.getTempo().add(tempoTotal);
		estatisticaMerge.getComparacoes().add(m.getComparacoes());
		estatisticaMerge.getCopias().add(m.getCopias());
		estatisticaMerge.getElementos().add(vetor.length);

	}

	/**
	 * Retorna uma lista de estat�sticas para itens do cenario 1
	 * 
	 * @return
	 */
	public List<Estatistica> getEstatisticas() {
		if (this.listEstatisticas == null) {
			this.listEstatisticas = new ArrayList<Estatistica>();
			this.listEstatisticas.add(estatisticaInteiros);
			this.listEstatisticas.add(estatisticaListaEncadeada);
			this.listEstatisticas.add(estatisticaRegistros);
		}
		return this.listEstatisticas;
	}

	/**
	 * Retorna uma lista de estat�sticas para itens do cenario 2
	 * 
	 * @return
	 */
	public List<Estatistica> getEstatisticasCenario2() {
		if (this.listEstatisticasCenario2 == null) {
			this.listEstatisticasCenario2 = new ArrayList<Estatistica>();
			this.listEstatisticasCenario2.add(estatisticaBasico);
			this.listEstatisticasCenario2.add(estatisticaInPlace);
			this.listEstatisticasCenario2.add(estatisticaIterativo);
			this.listEstatisticasCenario2.add(estatisticaMediano);
		}
		return this.listEstatisticasCenario2;
	}

	/**
	 * Retorna uma lista de estat�sticas para itens do cenario 3
	 * 
	 * @return
	 */
	public List<Estatistica> getEstatisticasCenario3() {
		if (this.listEstatisticasCenario3 == null) {
			this.listEstatisticasCenario3 = new ArrayList<Estatistica>();
			this.listEstatisticasCenario3.add(estatisticaInPlace);
			this.listEstatisticasCenario3.add(estatisticaMerge);
		}
		return this.listEstatisticasCenario3;
	}

	/**
	 * Salva arquivo csv com as estatisticas do algoritmos de ordena��o para o
	 * cenário 1
	 * 
	 * @throws IOException
	 */
	public void salvaEstatisticas() throws IOException {
		StringBuilder builder = extrairDadosEstatisticos(getEstatisticas());
		System.out.println(builder.toString());
		QuickSortUtils.saveFile("src/resultados/Cenario1.csv",
				builder.toString());
	}

	/**
	 * Salva arquivo csv com as estatisticas do algoritmos de ordena��o para o
	 * cenário 2
	 * 
	 * @throws IOException
	 */
	public void salvaEstatisticasCenario2() throws IOException {
		StringBuilder builder = extrairDadosEstatisticos(getEstatisticasCenario2());
		System.out.println(builder.toString());
		QuickSortUtils.saveFile("src/resultados/Cenario2.csv",
				builder.toString());

	}

	/**
	 * Salva arquivo csv com as estatisticas do algoritmos de ordena��o para o
	 * cenário 3
	 * 
	 * @throws IOException
	 */
	public void salvaEstatisticasCenario3() throws IOException {
		StringBuilder builder = extrairDadosEstatisticos(getEstatisticasCenario3());
		System.out.println(builder.toString());
		QuickSortUtils.saveFile("src/resultados/Cenario3.csv",
				builder.toString());

	}

	/**
	 * Extrai dados da lista de estatisticas
	 * 
	 * @param estatisticas
	 * @return StringBuilder
	 */
	private StringBuilder extrairDadosEstatisticos(
			List<Estatistica> estatisticas) {
		StringBuilder builder = new StringBuilder();

		// Navega pela lista de estatisticas para montar o arquivo de sa�da
		for (Estatistica estatistica : estatisticas) {
			builder.append(estatistica.getNome());
			for (int i = 0; i <= estatistica.getTempo().size(); i++) {
				builder.append(";");
			}
			builder.append("M�dia\n");

			// Navega pela lista de elementos(quantidade de itens do vetor) do
			// objeto de estatisticas
			builder.append("Numero de Elementos;");
			for (Integer tamanhoElementos : estatistica.getElementos()) {
				builder.append(tamanhoElementos);
				builder.append(";");
			}
			builder.append("\n");

			// Nvega pela lista de tempos do objeto de estatisticas
			builder.append("Tempo Total (ms);");
			for (Double tempo : estatistica.getTempo()) {
				builder.append(NumberFormat.getInstance().format(tempo));
				builder.append(";");
			}
			builder.append(estatistica.getMediaTempo());
			builder.append("\n");

			// Navega pela lista de comparacoes do objeto de estatisticas
			builder.append("Numero de Comparac�es;");
			for (Integer comparacao : estatistica.getComparacoes()) {
				builder.append(comparacao);
				builder.append(";");
			}
			builder.append(estatistica.getMediaComparacao());
			builder.append("\n");

			// Navega pela lista de copias do objeto de estatisticas
			builder.append("Numero de C�pias;");
			for (Integer copias : estatistica.getCopias()) {
				builder.append(copias);
				builder.append(";");
			}
			builder.append(estatistica.getMediaCopias());
			builder.append("\n");
			builder.append("\n");

		}
		return builder;
	}
}